/*
    Project:        Home Power Control
    File:           HPCLogger.cpp
    Author:         based on Logger from Claudio Scordino (http://retis.sssup.it/~scordino/code/logger.html)
                    redesign: christian@karunamusic.at
    Date:           12.2014
    Description:    Basic implementation of a logger-class to send logmessages with various loglevels
                    via signals to all connected subscribers.
 */

#include <iostream>
#include <new>
#include <cstdlib>
#include "HPCLogger.h"

// Definition (and initialization) of static attributes
HPCLogger* HPCLogger::m_Log = 0;

HPCLogMessage::HPCLogMessage(   const TLogLevel	    logLevel,
                                const std::string&  method,
                                const std::string&	sourceFile,
                                const unsigned int 	codeLine,
                                const std::string& 	message )
    :m_LogLevel(logLevel),m_Method(method),m_SourceFile(sourceFile),m_CodeLine(codeLine),m_Message(message)
{
    m_TimeStamp = dateTime();
}

const std::string HPCLogMessage::dateTime()
{
    time_t now = time(0);
    struct tm tstruct;
    char buf[80];

    tstruct = *localtime( &now );
    strftime( buf,sizeof(buf),"%d.%m.%Y %X",&tstruct );

    return buf;
}

std::ostream& operator << ( std::ostream& dest, const HPCLogMessage& msg )
{
    dest << "[" << msg.TimeStamp() << "]";
    if ( msg.LogLevel() == trace )
    {
        dest << "(" << msg.SourceFile() << "|" << msg.CodeLine() << "|" << msg.Method() << ")";
    }
    else if ( msg.LogLevel() == debug )
    {
        dest << "(" << msg.Method() << ")";
    }
    dest << ": " << msg.Message();
    return dest;
}

#ifdef LOGGER_MULTITHREAD
pthread_mutex_t HPCLogger::m_Lock = PTHREAD_MUTEX_INITIALIZER;
void HPCLogger::lock()
{
    pthread_mutex_lock(&m_Lock);
}

void HPCLogger::unlock()
{
    pthread_mutex_unlock(&m_Lock);
}
#else
void HPCLogger::lock() {}
void HPCLogger::unlock() {}
#endif



/**
 * \brief Constructor.
 * It is a private constructor, called only by getInstance() and only the
 * first time. It is called inside a lock, so lock inside this method
 * is not required.
 */
HPCLogger::HPCLogger()
{
}

/**
 * \brief Destructor.
 * It only closes the file, if open, and cleans memory.
 */

HPCLogger::~HPCLogger()
{
    HPCLogger::lock();
    delete m_Log;
    HPCLogger::unlock();

}

/**
 * \brief Method to get a reference to the object (i.e., Singleton)
 * It is a static method.
 * @return Reference to the object.
 */
HPCLogger& HPCLogger::getInstance()
{
    HPCLogger::lock();
    if (m_Log == 0)
        m_Log = new HPCLogger;
    HPCLogger::unlock();
    return *m_Log;
}

HPCLogger::connection_t HPCLogger::Register( const signal_t::slot_type &subscriber )
{
    HPCLogger::lock();
    connection_t ret = m_LogEvent.connect( subscriber );
    HPCLogger::unlock();
    return ret;
}

void HPCLogger::Unregister( connection_t subscriber )
{
    subscriber.disconnect();
}

/**
 * \brief Method used to print messages.
 * Called by the DEBUG() macro.
 * @param Priority of the message
 * @param Source file where the method has been called (set equal to __FILE__
 * 	      by the DEBUG macro)
 * @param Source line where the method has been called (set equal to __LINE__
          by the macro)
 * @param Message
 */
void HPCLogger::print(const TLogLevel    logLevel,
                      const std::string& method,
                      const std::string& sourceFile,
                      const unsigned int codeLine,
                      const std::string& message)
{
    if ( !message.length() )
        return;

    HPCLogger::lock();
    HPCLogMessage *lm = new HPCLogMessage(logLevel,method,sourceFile,codeLine,message);
    m_LogEvent(*lm);
    delete lm;
    HPCLogger::unlock();
}
